home *** CD-ROM | disk | FTP | other *** search
/ Carousel / CAROUSEL.cdr / mactosh / utilprn / hpdeskje.sit / HPDJet ƒ / BatchPrint ƒ / BatchPrint.Pas < prev    next >
Pascal/Delphi Source File  |  1989-04-21  |  68KB  |  2,221 lines

  1. { 21.04.1989  amn  (latest edit) }
  2.  
  3. {$U-}  {don't automatically include "Pascal Textbook" units}
  4. {$D+}  {MacsBug symbols}
  5.  
  6. PROGRAM BatchPrint;
  7.  
  8. { A program to print one or more spool files }
  9. { produced by the HPDJ printer driver. }
  10.  
  11. { Authors:  Ari Mujunen (amn@hutcs.hut.fi), }
  12. { Johan MyrÄen (jem@hutcs.hut.fi }
  13. { and Olli Arnberg (oar@hutcs.hut.fi). }
  14.  
  15. { Copyright Ari Mujunen, Johan MyrÄen, Olli Arnberg 1989. }
  16.  
  17. { You may redistribute this application (=application file, source files, }
  18. { documentation file(s), and the file 'Copyright and Source Offer') }
  19. { only _non-commercially_ and _in its entirety_. }
  20. { See the file 'BatchPrint Copyright' and/or documentation for details. }
  21. { Acknowledgements:  Special thanks to Mr. Paul DuBois and Mr. Owen Hartnett }
  22. { for the TransSkel 2.0 application skeleton. }
  23.  
  24. { Change history: }
  25. { Version  Date        Who  Why }
  26. { 0.0      31.03.1989  amn      Original version. }
  27. {          02.04.1989  amn      Windows, menus. }
  28. {          05.04.1989  amn,oar  More windows, menus. }
  29. {          11.04.1989  amn      Printing. }
  30. {          12.04.1989  amn      Cleaning up. }
  31. {          13.04.1989  amn      Settings and Page menus. }
  32. {          14.04.1989  jem      Scroll bars. }
  33. {          15.04.1989  amn,jem  More scroll bars. }
  34. {          16.04.1989  amn,jem  Goto Page, Scale Preview and general tidying. }
  35. {          17.04.1989  amn      "No windows" menu state. }
  36. {          20.04.1989  amn      Print only pages needed. }
  37. {          21.04.1989  amn,jem  Print All didn't work. }
  38.  
  39.  
  40. {$B+}  {Bundle bit on, we have icons etc. }
  41. {$T APPL^89s}  {File type 'APPL', creator '^89s'.}
  42. {$R BatchPrint.Rsrc}  {Identify resource file.}
  43.  
  44. {$U TransSkel}  {Unit 'TransSkel' is found in the file 'TransSkel'.}
  45. USES
  46.   MemTypes,
  47.   QuickDraw,
  48.   OSIntf,
  49.   ToolIntf,
  50.   PackIntf,
  51.   MacPrint,
  52.   TransSkel;
  53.   
  54.   
  55.   CONST
  56.     cMagicalWidthOfScrollBars = 16;  {pixels as required by WDEF 0}
  57.     cViewScalePercentageDefault = 100;
  58.     cNumberOfPixelsAroundPage= 16;
  59.     
  60.     { Resource id's: }
  61.     { 'STR ': }
  62.     cStringAboutBatchPrint = 128;
  63.     cStringNumberOfPages = 129;
  64.     cStringPage = 130;
  65.     cStringWindowTitleAt100Percent = 131;
  66.     cStringWindowTitleAtOtherPercentages = 132;
  67.     cStringUnderMinimum = 133;
  68.     cStringOverMaximum = 134;
  69.     
  70.     { 'MENU': }
  71.     cMenuFirstId = 128;
  72.     
  73.     { 'ALRT': }
  74.     cAlertAboutBatchPrint = 128;
  75.     cAlertNoMemoryForWindows = 129;
  76.     cAlertFileError = 130;
  77.     cAlertPrintError = 131;
  78.     cAlertScalingPercentageOutOfBounds = 134;
  79.     
  80.     { 'WIND': }
  81.     cWindowOrdinary = 128;
  82.     cWindowZoomable = 129;
  83.     
  84.     { 'DLOG': }
  85.     cDialogScalePreview = 132;
  86.     cDialogGotoPage = 133;
  87.     
  88.     { Menu item numbers: }
  89.     cFileOpen = 1;
  90.     cFileClose = 3;
  91.     cFileCloseAll = 4;
  92.     cFilePageSetup = 6;
  93.     cFilePageSetupAll = 7;
  94.     cFilePrint = 8;
  95.     cFilePrintAll = 9;
  96.     cFileQuit = 11;
  97.     
  98.     cEditUndo = 1;
  99.     cEditCut  = 3;
  100.     cEditCopy = 4;
  101.     cEditPaste = 5;
  102.     cEditClear = 6;
  103.     
  104.     cViewInformation = 1;
  105.     cViewContents = 2;
  106.     cViewScalePreview = 4;
  107.     
  108.     cSettingsUsePrinterSpacing = 1;
  109.     cSettingsDisableFontScaling = 2;
  110.     
  111.     cPagePrevious = 1;
  112.     cPageNext = 2;
  113.     cPageFirst = 4;
  114.     cPageLast = 5;
  115.     cPageGotoPage = 7;
  116.     cPagePageNumberItem = 8;
  117.     
  118.     { General dialog button item numbers: }
  119.     cOkButton = 1;
  120.     cCancelButton = 2;
  121.     
  122.     { Scale Preview Dialog items: }
  123.     cDITScalePercentage = 4;
  124.     
  125.     { Goto Page Dialog items: }
  126.     cDITPageNumber = 4;
  127.     
  128.     
  129.   
  130.   TYPE
  131.     tWindowRelatedInfo=
  132.       RECORD
  133.         rSpoolFileHeader: TPfHeader;  {must be first; read directly from file}
  134.         rOriginalPageRect: Rect;
  135.         rSFReply: SFReply;
  136.         rViewMenuSelectionForThisWindow: Integer;
  137.         rViewSize: ARRAY [cViewInformation..cViewContents] OF Rect;
  138.         rViewScalePreviewPercentage: Integer;
  139.         rUsePrinterSpacing: Boolean;
  140.         rDisableFontScaling: Boolean;
  141.         rPageNumber: Integer;
  142.         rVerticalScrollControl,
  143.         rHorizontalScrollControl: ControlHandle;
  144.       END;
  145.     tpWindowRelatedInfo= ^tWindowRelatedInfo;
  146.     thWindowRelatedInfo= ^tpWindowRelatedInfo;
  147.     
  148.     tMenuEnumeration=(
  149.       eFile,
  150.       eEdit,
  151.       eView,
  152.       eSettings,
  153.       ePage
  154.     );
  155.     
  156.  
  157.   VAR
  158.     { Global variables. }
  159.     vMenu: ARRAY [tMenuEnumeration] OF MenuHandle;
  160.     vHas128KROMs: Boolean;
  161.     vNumberOfOurOpenWindows: Integer;
  162.     { Global settings. }
  163.     vViewMenuSelectionDefault: Integer;
  164.     vViewScalePercentageDefault: Integer;
  165.     vSettingsUsePrinterSpacing: Boolean;
  166.     vSettingsDisableFontScaling: Boolean;
  167.     { For pOurGetPicProc. }
  168.     vGlobalSpoolFileRefNumDuringOnePageUpdate: Integer;
  169.     
  170.     { Instructions from the Finder. }
  171.     vWhatFinderToldUsToDo: Integer;
  172.     vNumberOfAppFiles: Integer;
  173.     
  174.     { Auxiliary variables for the main program. }
  175.     vMenuEnumeration: tMenuEnumeration;
  176.     hString: StringHandle;
  177.     successful: Boolean;
  178.     i: Integer;
  179.     theAppFile: AppFile;
  180.     romVersion: Integer;
  181.     machineType: Integer;
  182.   
  183.   
  184.   PROCEDURE pErrorAlert(theAlert: Integer);
  185.     VAR
  186.       buttonClicked: Integer;
  187.   BEGIN
  188.     buttonClicked := StopAlert(theAlert, NIL);
  189.   END;  {pErrorAlert}
  190.   
  191.   
  192.   PROCEDURE pFileErrorAlert(
  193.     theAlert: Integer;
  194.     retCode: OSErr;
  195.     fileName: Str255
  196.   );
  197.     VAR
  198.       errorNumberAsString: Str255;
  199.   BEGIN
  200.     NumToString(Longint(retCode), errorNumberAsString);
  201.     ParamText(errorNumberAsString, fileName, '', '');
  202.     pErrorAlert(theAlert);
  203.   END;  {pFileErrorAlert}
  204.   
  205.   
  206.   PROCEDURE pPrintErrorAlert(
  207.     theAlert: Integer;
  208.     retCode: OSErr
  209.   );
  210.     VAR
  211.       errorNumberAsString: Str255;
  212.   BEGIN
  213.     NumToString(Longint(retCode), errorNumberAsString);
  214.     ParamText(errorNumberAsString, '', '', '');
  215.     pErrorAlert(theAlert);
  216.   END;  {pPrintErrorAlert}
  217.   
  218.   
  219.   FUNCTION fParametrizeSTR(
  220.     strId: Integer;
  221.     stringUsedIfResNotFound: Str255;
  222.     p0,
  223.     p1: Str255
  224.   ) : Str255;
  225.     VAR
  226.       hString: StringHandle;
  227.       result: Str255;
  228.       i: Integer;
  229.   BEGIN
  230.     hString := GetString(strId);
  231.     IF hString = NIL THEN
  232.       result := stringUsedIfResNotFound
  233.     ELSE
  234.       result := hString^^;
  235.     
  236.     i := Pos('^0', result);
  237.     IF i > 0 THEN
  238.       BEGIN
  239.         Delete(result, i, 2);
  240.         Insert(p0, result, i);
  241.       END;
  242.     
  243.     i := Pos('^1', result);
  244.     IF i > 0 THEN
  245.       BEGIN
  246.         Delete(result, i, 2);
  247.         Insert(p1, result, i);
  248.       END;
  249.     fParametrizeSTR := result;
  250.   END;  {fParametrizeSTR}
  251.     
  252.   
  253.   PROCEDURE pDoAboutBatchPrint;
  254.     VAR
  255.       buttonClicked: Integer;
  256.   BEGIN
  257.     buttonClicked := Alert(cAlertAboutBatchPrint, NIL);
  258.   END;  {pDoAboutBatchPrint}
  259.   
  260.   
  261.   CONST
  262.     cPageNumberBoxPart = 5;  {1/5 th part of horizontal scroller for page number}
  263.   
  264.   PROCEDURE pCalcHorizontalScrollRect(theWindow: WindowPtr; VAR r: Rect);
  265.     VAR
  266.       width: Integer;
  267.   BEGIN
  268.     r := theWindow^.portRect;
  269.     r.right := r.right - cMagicalWidthOfScrollBars + 2;
  270.     r.left := r.left - 1;
  271.     r.bottom := r.bottom + 1;
  272.     r.top := r.bottom - cMagicalWidthOfScrollBars;
  273.     width := (r.right - r.left) DIV cPageNumberBoxPart;
  274.     r.right := r.right - width;
  275.   END;  {pCalcHorizontalScrollRect}
  276.   
  277.   
  278.   PROCEDURE pCalcPageNumberRect(theWindow: WindowPtr; VAR r: Rect);
  279.     VAR
  280.       width: Integer;
  281.   BEGIN
  282.     r := theWindow^.portRect;
  283.     r.right := r.right - cMagicalWidthOfScrollBars + 2;
  284.     r.left := r.left - 1;
  285.     r.bottom := r.bottom + 1;
  286.     r.top := r.bottom - cMagicalWidthOfScrollBars;
  287.     width := (r.right - r.left) DIV cPageNumberBoxPart;
  288.     r.left := r.right - width;
  289.   END;  {pCalcHorizontalScrollRect}
  290.   
  291.   
  292.   PROCEDURE pCalcVerticalScrollRect(theWindow: WindowPtr; VAR r: Rect);
  293.   BEGIN
  294.     r := theWindow^.portRect;
  295.     r.right := r.right + 1;
  296.     r.left := r.right - cMagicalWidthOfScrollBars;
  297.     r.bottom := r.bottom - cMagicalWidthOfScrollBars + 2;
  298.     r.top := r.top - 1;
  299.   END;  {pCalcVerticalScrollRect}
  300.   
  301.   
  302.   PROCEDURE pCalcDocumentRect(theWindow: WindowPtr; VAR docRect: Rect);
  303.     {VAR}
  304.       {savePort: GrafPtr;}
  305.   BEGIN
  306.     {This does not work for hidden windows:}
  307.     {GetPort(savePort);}
  308.     {SetPort(theWindow);}
  309.     {docRect := WindowPeek(theWindow)^.contRgn^^.rgnBBox;}
  310.     {GlobalToLocal(docRect.topLeft);}
  311.     {GlobalToLocal(docRect.botRight);}
  312.     
  313.     docRect := theWindow^.portRect;
  314.     docRect.right :=
  315.       docRect.right - cMagicalWidthOfScrollBars + 1;
  316.     docRect.bottom :=
  317.       docRect.bottom - cMagicalWidthOfScrollBars + 1;
  318.     {SetPort(savePort);}
  319.   END;  {pCalcDocumentRect}
  320.   
  321.   
  322.   PROCEDURE pCalcScaledPageDrawingRect(
  323.     vhWindowRelatedInfo: thWindowRelatedInfo
  324.   );
  325.     VAR
  326.       dstRect: Rect;
  327.       r1, r2: Rect;
  328.   BEGIN
  329.     dstRect := vhWindowRelatedInfo^^.rOriginalPageRect;
  330.     SetRect(r1, 0, 0, 100, 100);
  331.     SetRect(r2, 0, 0, vhWindowRelatedInfo^^.rViewScalePreviewPercentage, 0);
  332.     r2.bottom := r2.right;
  333.     MapRect(dstRect, r1, r2);
  334.     vhWindowRelatedInfo^^.rViewSize[cViewContents] := dstRect;
  335.   END;  {pCalcScaledPageDrawingRect}
  336.   
  337.   
  338.   PROCEDURE pUpdateWindow(resized: Boolean);  FORWARD;
  339.   
  340.   
  341.   PROCEDURE pScrollWindow(dh, dv: Integer; theScroll: ControlHandle);
  342.     VAR
  343.       vScrollingRect: Rect;
  344.       hUpdateRgn: RgnHandle;
  345.       saveVisRgn: RgnHandle;
  346.       theWindow: WindowPtr;
  347.   BEGIN
  348.     IF (dh=0) AND (dv=0) THEN
  349.       Exit;
  350.     
  351.     hUpdateRgn := NewRgn;
  352.     IF hUpdateRgn = NIL THEN
  353.       BEGIN
  354.         pErrorAlert(cAlertNoMemoryForWindows);  {??? no memory for update...}
  355.         Exit;
  356.       END;
  357.  
  358.     pCalcDocumentRect(theScroll^^.contrlOwner, vScrollingRect);
  359.  
  360.     ScrollRect(vScrollingRect, -dh, -dv, hUpdateRgn);
  361.     
  362.     { Minor modifications to visRgn before misusing our update proc. }
  363.     GetPort(theWindow);
  364.     saveVisRgn := theWindow^.visRgn;
  365.     theWindow^.visRgn := hUpdateRgn;
  366.     pUpdateWindow( {resized=>} False);
  367.     theWindow^.visRgn := saveVisRgn;
  368.  
  369.     DisposeRgn(hUpdateRgn);
  370.   END; {pScrollWindow}
  371.  
  372.  
  373.   PROCEDURE pHorizontalScrollAction(
  374.     theScroll: ControlHandle;
  375.     partCode: Integer
  376.   );
  377.     VAR
  378.       docRect: Rect;
  379.       vDelta: Integer;
  380.       savedValue: Integer;
  381.   BEGIN
  382.     pCalcDocumentRect(theScroll^^.contrlOwner, docRect);
  383.     vDelta := (docRect.right - docRect.left) DIV 10; {one tenth of width} 
  384.     CASE partCode OF
  385.       inUpButton: vDelta := -vDelta;
  386.       inDownButton: vDelta := vDelta;
  387.       inPageUp: vDelta := -9*vDelta;
  388.       inPageDown: vDelta := 9*vDelta;
  389.       OTHERWISE vDelta := 0;
  390.     END;
  391.     
  392.     { Let Control Manager do "endpoint bumping". }
  393.     savedValue := GetCtlValue(theScroll);
  394.     SetCtlValue(theScroll, savedValue + vDelta);
  395.     vDelta := GetCtlValue(theScroll) - savedValue;
  396.     
  397.     pScrollWindow(vDelta, 0, theScroll);
  398.   END; {pHorizontalScrollAction}
  399.  
  400.  
  401.   PROCEDURE pVerticalScrollAction(
  402.     theScroll: ControlHandle;
  403.     partCode: Integer
  404.   );
  405.     VAR
  406.       docRect: Rect;
  407.       vDelta: Integer;
  408.       savedValue: Integer;
  409.   BEGIN
  410.     pCalcDocumentRect(theScroll^^.contrlOwner, docRect);
  411.     vDelta := (docRect.bottom - docRect.top) DIV 10; {one tenth of height} 
  412.     CASE partCode OF
  413.       inUpButton: vDelta := -vDelta;
  414.       inDownButton: vDelta := vDelta;
  415.       inPageUp: vDelta := -9*vDelta;
  416.       inPageDown: vDelta := 9*vDelta;
  417.       OTHERWISE vDelta := 0;
  418.     END;
  419.     
  420.     { Let Control Manager do "endpoint bumping". }
  421.     savedValue := GetCtlValue(theScroll);
  422.     SetCtlValue(theScroll, savedValue + vDelta);
  423.     vDelta := GetCtlValue(theScroll) - savedValue;
  424.     
  425.     pScrollWindow(0, vDelta, theScroll);
  426.   END; {pVerticalScrollAction}
  427.   
  428.   
  429.   PROCEDURE pSetScrollBarLimits(theWindow: WindowPtr);
  430.     VAR
  431.       vhWindowRelatedInfo: thWindowRelatedInfo;
  432.       savedState: SignedByte;
  433.       pageRect: Rect;
  434.       docRect: Rect;
  435.       maximumOrigin: Point;
  436.   BEGIN
  437.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  438.     
  439.     IF vHas128KRoms THEN
  440.       savedState := HGetState(Handle(vhWindowRelatedInfo))
  441.     ELSE
  442.       savedState := Ptr(Handle(vhWindowRelatedInfo)^)^;
  443.     HLock(Handle(vhWindowRelatedInfo));
  444.     WITH vhWindowRelatedInfo^^ DO
  445.       BEGIN
  446.         pageRect := rViewSize[rViewMenuSelectionForThisWindow];
  447.         
  448.         { Reveal a part of grey background. }
  449.         InsetRect(pageRect,
  450.           -cNumberOfPixelsAroundPage,
  451.           -cNumberOfPixelsAroundPage
  452.         );
  453.           
  454.         pCalcDocumentRect(theWindow, docRect);
  455.         maximumOrigin.v := pageRect.bottom - (docRect.bottom - docRect.top);
  456.         IF maximumOrigin.v < pageRect.top THEN
  457.           maximumOrigin.v := pageRect.top;
  458.         maximumOrigin.h := pageRect.right - (docRect.right - docRect.left);
  459.         IF maximumOrigin.h < pageRect.left THEN
  460.           maximumOrigin.h := pageRect.left;
  461.         
  462.         SetCtlMin(rVerticalScrollControl, pageRect.top);
  463.         SetCtlMax(rVerticalScrollControl, maximumOrigin.v);
  464.         SetCtlMin(rHorizontalScrollControl, pageRect.left);
  465.         SetCtlMax(rHorizontalScrollControl, maximumOrigin.h);
  466.       END;  {WITH}
  467.     IF vHas128KRoms THEN
  468.       HSetState(Handle(vhWindowRelatedInfo), savedState)
  469.     ELSE
  470.       Ptr(Handle(vhWindowRelatedInfo)^)^ := savedState;
  471.   END;  {pSetScrollBarLimits}
  472.   
  473.   
  474.   TYPE
  475.     tProgramState=(
  476.       eNoOurWindowsOpen,
  477.       eAtLeastOneOurWindowOpen
  478.     );
  479.   
  480.   PROCEDURE pChangeViewMenuAccordingToWindow(theWindow: WindowPtr);  FORWARD;
  481.   PROCEDURE pChangeSettingsMenuAccordingToWindow(theWindow: WindowPtr);  FORWARD;
  482.   
  483.   PROCEDURE pMenusToState(vProgramState: tProgramState);
  484.   BEGIN
  485.     CASE vProgramState OF
  486.       eNoOurWindowsOpen:
  487.         BEGIN
  488.           DisableItem(vMenu[eFile], cFileClose);
  489.           DisableItem(vMenu[eFile], cFileCloseAll);
  490.           DisableItem(vMenu[eFile], cFilePageSetup);
  491.           DisableItem(vMenu[eFile], cFilePageSetupAll);
  492.           DisableItem(vMenu[eFile], cFilePrint);
  493.           DisableItem(vMenu[eFile], cFilePrintAll);
  494.           
  495.           EnableItem(vMenu[eEdit], cEditUndo);
  496.           EnableItem(vMenu[eEdit], cEditCut);
  497.           EnableItem(vMenu[eEdit], cEditCopy);
  498.           EnableItem(vMenu[eEdit], cEditPaste);
  499.           EnableItem(vMenu[eEdit], cEditClear);
  500.           
  501.           pChangeViewMenuAccordingToWindow(NIL);
  502.           pChangeSettingsMenuAccordingToWindow(NIL);
  503.           
  504.           DisableItem(vMenu[ePage], cPagePrevious);
  505.           DisableItem(vMenu[ePage], cPageNext);
  506.           DisableItem(vMenu[ePage], cPageFirst);
  507.           DisableItem(vMenu[ePage], cPageLast);
  508.           DisableItem(vMenu[ePage], cPageGotoPage);
  509.         END;
  510.       eAtLeastOneOurWindowOpen:
  511.         BEGIN
  512.           EnableItem(vMenu[eFile], cFileClose);
  513.           EnableItem(vMenu[eFile], cFileCloseAll);
  514.           EnableItem(vMenu[eFile], cFilePageSetup);
  515.           EnableItem(vMenu[eFile], cFilePageSetupAll);
  516.           EnableItem(vMenu[eFile], cFilePrint);
  517.           EnableItem(vMenu[eFile], cFilePrintAll);
  518.           
  519.           DisableItem(vMenu[eEdit], cEditUndo);
  520.           DisableItem(vMenu[eEdit], cEditCut);
  521.           DisableItem(vMenu[eEdit], cEditCopy);
  522.           DisableItem(vMenu[eEdit], cEditPaste);
  523.           DisableItem(vMenu[eEdit], cEditClear);
  524.           
  525.           EnableItem(vMenu[ePage], cPagePrevious);
  526.           EnableItem(vMenu[ePage], cPageNext);
  527.           EnableItem(vMenu[ePage], cPageFirst);
  528.           EnableItem(vMenu[ePage], cPageLast);
  529.           EnableItem(vMenu[ePage], cPageGotoPage);
  530.         END;
  531.     END;
  532.   END;  {pMenusToState}
  533.   
  534.   
  535.   PROCEDURE pRetitleWindow(theWIndow: WindowPtr);
  536.     VAR
  537.       vhWindowRelatedInfo: thWindowRelatedInfo;
  538.       name: Str255;
  539.       scalePercentage: Integer;
  540.       scalePercentageAsString: Str255;
  541.       titleString: Str255;
  542.   BEGIN
  543.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  544.     name := vhWindowRelatedInfo^^.rSFReply.fName;
  545.     scalePercentage := vhWindowRelatedInfo^^.rViewScalePreviewPercentage;
  546.     NumToString(Longint(scalePercentage), scalePercentageAsString);
  547.     
  548.     IF scalePercentage = 100 THEN
  549.       titleString := fParametrizeSTR(
  550.         cStringWindowTitleAt100Percent,
  551.         '^0',
  552.         name,
  553.         scalePercentageAsString
  554.       )
  555.     ELSE
  556.       titleString := fParametrizeSTR(
  557.         cStringWindowTitleAtOtherPercentages,
  558.         '^0 at ^1%',
  559.         name,
  560.         scalePercentageAsString
  561.       );
  562.     
  563.     SetWTitle(theWindow, titleString);
  564.   END;  {pRetitleWindow}
  565.   
  566.   
  567.   FUNCTION fCreateWindow(
  568.     VAR theWindow: WindowPtr;
  569.     vSFReply: SFReply
  570.   ) : Boolean;
  571.   
  572.     LABEL
  573.       closeFile;
  574.     CONST
  575.       cDropDown= 30;
  576.       cDropRight= 20;
  577.     VAR
  578.       previousFrontWindow: WindowPtr;
  579.       newTopLeft: Point;
  580.       vhWindowRelatedInfo: thWindowRelatedInfo;
  581.       hScrollBar: ControlHandle;
  582.       vScrollBarRect: Rect;
  583.       windowRelatedInfoSuccessfullyRead: Boolean;
  584.       fileRefNum: Integer;
  585.       numberOfBytes: LongInt;
  586.       retCode: OSErr;
  587.       
  588.   BEGIN
  589.     previousFrontWindow := FrontWindow;
  590.     
  591.     { Create (an invisible) window from appropriate template }
  592.     { and let it be backmost (to prevent generating activate events now). }
  593.     IF vHas128KROMs THEN
  594.       theWindow := GetNewWindow(cWindowZoomable, NIL, {behind=>} NIL)
  595.     ELSE
  596.       theWindow := GetNewWindow(cWindowOrdinary, NIL, {behind=>} NIL);
  597.     IF theWindow = NIL THEN
  598.       BEGIN
  599.         pErrorAlert(cAlertNoMemoryForWindows);
  600.         fCreateWindow := False;
  601.         Exit;
  602.       END;
  603.     
  604.     { Drop window nicely below the current topmost window. }
  605.     WITH newTopLeft DO
  606.       IF previousFrontWindow = NIL THEN
  607.         BEGIN
  608.           v := -theWindow^.portBits.bounds.top;
  609.           h := -theWindow^.portBits.bounds.left;
  610.         END
  611.       ELSE
  612.         BEGIN
  613.           v := -previousFrontWindow^.portBits.bounds.top + cDropDown;
  614.           h := -previousFrontWindow^.portBits.bounds.left + cDropRight;
  615.         END;
  616.     { Move only if top left is visible on screen. }
  617.     IF PtInRect(newTopLeft, screenBits.bounds) THEN
  618.       MoveWindow(theWindow, newTopLeft.h, newTopLeft.v, {front=>} True)
  619.     ELSE
  620.       ;  {leaves the window in the position defined in the WIND resource}
  621.     
  622.     { Create our additional storage for this window. }
  623.     vhWindowRelatedInfo := thWindowRelatedInfo(NewHandle(Sizeof(tWindowRelatedInfo)));
  624.     IF vhWindowRelatedInfo = NIL THEN
  625.       BEGIN
  626.         pErrorAlert(cAlertNoMemoryForWindows);
  627.         DisposeWindow(theWindow);
  628.         fCreateWindow := False;
  629.         Exit;
  630.       END;
  631.     SetWRefCon(theWindow, Longint(vhWindowRelatedInfo));
  632.     
  633.     { Create scroll bars. }
  634.     pCalcHorizontalScrollRect(theWindow, vScrollBarRect);
  635.     hScrollBar := NewControl(
  636.       theWindow,
  637.       vScrollBarRect,
  638.       '',
  639.       {visible=>} False,
  640.       0,0,0,
  641.       scrollBarProc,
  642.       {refCon=>} 0
  643.     );
  644.     IF hScrollBar = NIL THEN
  645.       BEGIN
  646.         pErrorAlert(cAlertNoMemoryForWindows);
  647.         DisposHandle(Handle(vhWindowRelatedInfo));
  648.         DisposeWindow(theWindow);
  649.         fCreateWindow := False;
  650.         Exit;
  651.       END;
  652.     SetCtlAction(hScrollBar, @pHorizontalScrollAction);
  653.     vhWindowRelatedInfo^^.rHorizontalScrollControl := hScrollBar;
  654.     
  655.     pCalcVerticalScrollRect(theWindow, vScrollBarRect);
  656.     hScrollBar := NewControl(
  657.       theWindow,
  658.       vScrollBarRect,
  659.       '',
  660.       {visible=>} False,
  661.       0,0,0,
  662.       scrollBarProc,
  663.       {refCon=>} 0
  664.     );
  665.     IF hScrollBar = NIL THEN
  666.       BEGIN
  667.         pErrorAlert(cAlertNoMemoryForWindows);
  668.         { No need to dispose controls created this far (IM I-321). }
  669.         DisposHandle(Handle(vhWindowRelatedInfo));
  670.         DisposeWindow(theWindow);
  671.         fCreateWindow := False;
  672.         Exit;
  673.       END;
  674.     SetCtlAction(hScrollBar, @pVerticalScrollAction);
  675.     vhWindowRelatedInfo^^.rVerticalScrollControl := hScrollBar;
  676.     
  677.     { Set viewing way from global defaults. }
  678.     vhWindowRelatedInfo^^.rViewMenuSelectionForThisWindow := 
  679.       vViewMenuSelectionDefault;
  680.     vhWindowRelatedInfo^^.rViewScalePreviewPercentage :=
  681.       vViewScalePercentageDefault;
  682.     vhWindowRelatedInfo^^.rUsePrinterSpacing := vSettingsUsePrinterSpacing;
  683.     vhWindowRelatedInfo^^.rDisableFontScaling := vSettingsDisableFontScaling;
  684.     vhWindowRelatedInfo^^.rPageNumber := 1;
  685.     
  686.     { Set file name etc., read spool file header. }
  687.     vhWindowRelatedInfo^^.rSFReply := vSFReply;
  688.     windowRelatedInfoSuccessfullyRead := False;
  689.     HLock(Handle(vhWindowRelatedInfo));
  690.     WITH vhWindowRelatedInfo^^.rSFReply DO
  691.       BEGIN
  692.         retCode := FSOpen(fName, vRefNum, fileRefNum);
  693.         IF retCode = noErr THEN
  694.           BEGIN
  695.             { Read print file header from start of the file. }
  696.             retCode := SetFPos(
  697.               fileRefNum,
  698.               fsFromStart,
  699.               0
  700.             );
  701.             IF retCode <> noErr THEN
  702.               BEGIN
  703.                 pFileErrorAlert(cAlertFileError, retCode, fName);
  704.                 GOTO closeFile;
  705.               END;
  706.               
  707.             numberOfBytes := Sizeof(TPfHeader);
  708.             retCode := FSRead(
  709.               fileRefNum,
  710.               numberOfBytes,
  711.               Ptr(vhWindowRelatedInfo^)
  712.             );
  713.             IF retCode <> noErr THEN
  714.               BEGIN
  715.                 pFileErrorAlert(cAlertFileError, retCode, fName);
  716.                 GOTO closeFile;
  717.               END;
  718.             windowRelatedInfoSuccessfullyRead := True;
  719.                           
  720.           closeFile:
  721.             retCode := FSClose(fileRefNum);
  722.           END
  723.         ELSE
  724.           BEGIN
  725.             pFileErrorAlert(cAlertFileError, retCode, fName);
  726.           END;
  727.       END;  {WITH}
  728.     
  729.     IF NOT windowRelatedInfoSuccessfullyRead THEN
  730.       BEGIN
  731.         { No need to dispose controls created this far (IM I-321). }
  732.         DisposHandle(Handle(vhWindowRelatedInfo));
  733.         DisposeWindow(theWindow);
  734.         fCreateWindow := False;
  735.         Exit;
  736.       END;
  737.  
  738.     { Quite a surprising place to set document sizes for all different }
  739.     { viewing alternatives (currently cViewInformation/cViewContents). }
  740.     WITH vhWindowRelatedInfo^^ DO
  741.       BEGIN
  742.         { Info will require as much space as the initial window is. }
  743.         pCalcDocumentRect(theWindow, rViewSize[cViewInformation]);
  744.         rViewSize[cViewInformation].bottom :=
  745.           rViewSize[cViewInformation].bottom - 2*cNumberOfPixelsAroundPage;
  746.         rViewSize[cViewInformation].right :=
  747.           rViewSize[cViewInformation].right - 2*cNumberOfPixelsAroundPage;
  748.         
  749.         { Contents according to page rect when spool file created. }
  750.         rOriginalPageRect := rSpoolFileHeader.Print.PrInfo.rPage;
  751.         pCalcScaledPageDrawingRect(vhWindowRelatedInfo);  {changes rViewSize[cViewContents]}
  752.         pSetScrollBarLimits(theWindow);
  753.         SetCtlValue(rVerticalScrollControl, -cNumberOfPixelsAroundPage);  {top}
  754.         SetCtlValue(rHorizontalScrollControl, -cNumberOfPixelsAroundPage);  {left}
  755.       END;  {WITH}
  756.     
  757.     HUnlock(Handle(vhWindowRelatedInfo));
  758.     
  759.     pRetitleWindow(theWindow);
  760.         
  761.     SelectWindow(theWindow);
  762.     ShowWindow(theWindow);
  763.     
  764.     IF vNumberOfOurOpenWindows <= 0 THEN
  765.       pMenusToState(eAtLeastOneOurWindowOpen);
  766.     vNumberOfOurOpenWindows := vNumberOfOurOpenWindows + 1;
  767.     fCreateWindow := windowRelatedInfoSuccessfullyRead;
  768.   END;  {fCreateWindow}
  769.   
  770.   
  771.   PROCEDURE pDisposeAllStructuresRelatedToThisWindow(theWindow: WindowPtr);
  772.     VAR
  773.       vhWindowRelatedInfo: thWindowRelatedInfo;
  774.   BEGIN
  775.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  776.     IF vhWindowRelatedInfo <> NIL THEN
  777.       IF GetHandleSize(Handle(vhWindowRelatedInfo)) = Sizeof(tWindowRelatedInfo) THEN
  778.         BEGIN
  779.           DisposHandle(Handle(vhWindowRelatedInfo));
  780.           DisposeWindow(theWindow);
  781.           { DisposeWindow will KillControls (IM I-321).}
  782.         END;
  783.   END;  {pDisposeAllStructuresRelatedToThisWindow}
  784.  
  785.  
  786.   PROCEDURE pDisposeAllStructuresRelatedToCurrentWindow;
  787.     VAR
  788.       theWindow: WindowPtr;
  789.   BEGIN
  790.     GetPort(theWindow);  {TransSkel makes the window to be deleted current.}
  791.     pDisposeAllStructuresRelatedToThisWindow(theWindow);
  792.   END;  {pDisposeAllStructuresRelatedToCurrentWindow}
  793.  
  794.  
  795.   PROCEDURE pInvalidateAllOfWindow(theWindow: WindowPtr);
  796.     VAR
  797.       savePort: GrafPtr;
  798.       contentRegionInLocalCoordinates: RgnHandle;
  799.   BEGIN
  800.     GetPort(savePort);
  801.     SetPort(theWindow);
  802.     contentRegionInLocalCoordinates := NewRgn;
  803.     CopyRgn(WindowPeek(theWindow)^.contRgn, contentRegionInLocalCoordinates);
  804.     OffsetRgn(contentRegionInLocalCoordinates,
  805.       theWindow^.portBits.bounds.left,
  806.       theWindow^.portBits.bounds.top
  807.     );
  808.     InvalRgn(contentRegionInLocalCoordinates);  {must be redrawn}
  809.     DisposeRgn(contentRegionInLocalCoordinates);
  810.     SetPort(savePort);
  811.   END;  {pInvalidateAllOfWindow}
  812.   
  813.   
  814.   PROCEDURE pMouseInWindow(
  815.     thePoint: Point;
  816.     theTime: Longint;
  817.     theMods: Integer
  818.   );
  819.     VAR
  820.       theWindow: WindowPtr;
  821.       theControl: ControlHandle;
  822.       vControlPartCode: Integer;
  823.       vNewCtlValue, vOldCtlValue: Integer;
  824.       vhWindowRelatedInfo: thWindowRelatedInfo;
  825.   BEGIN
  826.     GetPort(theWindow);
  827.     vControlPartCode := FindControl(thePoint, theWindow, theControl);
  828.     IF vControlPartCode = 0 THEN
  829.       Exit;
  830.     
  831.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  832.     IF vControlPartCode = inThumb THEN
  833.       BEGIN
  834.         vOldCtlValue := GetCtlValue(theControl);
  835.         vControlPartCode := TrackControl(theControl, thePoint, NIL);
  836.         IF theControl = vhWindowRelatedInfo^^.rHorizontalScrollControl THEN
  837.           pScrollWindow(
  838.             GetCtlValue(theControl) - vOldCtlValue,
  839.             0,
  840.             theControl
  841.           )
  842.         ELSE IF theControl = vhWindowRelatedInfo^^.rVerticalScrollControl THEN
  843.           pScrollWindow(
  844.             0,
  845.             GetCtlValue(theControl) - vOldCtlValue,
  846.             theControl
  847.           )
  848.         ELSE
  849.           ;
  850.       END  {IF inThumb}
  851.     ELSE
  852.       vControlPartCode := TrackControl(
  853.         theControl,
  854.         thePoint,
  855.         POINTER(-1)  {uses the procedure set into the control record }
  856.       );
  857.   END; {pMouseInWindow}        
  858.  
  859.  
  860.   PROCEDURE pUpdateWindowInformation(
  861.     theWindow: WindowPtr;  {for convenience; must be current GrafPort}
  862.     vhWindowRelatedInfo: thWindowRelatedInfo;  {must be locked}
  863.     needErasing: Boolean
  864.   );
  865.     VAR
  866.       vString: Str255;
  867.   BEGIN
  868.     IF needErasing THEN
  869.       EraseRgn(theWindow^.visRgn);
  870.     
  871.     MoveTo(30, 10);
  872.     DrawString(vhWindowRelatedInfo^^.rSFReply.fName);
  873.     
  874.     MoveTo(30, 30);
  875.     NumToString(
  876.       LongInt(vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages),
  877.       vString
  878.     );
  879.     vString := fParametrizeSTR(
  880.       cStringNumberOfPages,
  881.       'Number Of Pages: ^0',
  882.       vString,
  883.       ''
  884.     );
  885.     DrawString(vString);
  886.   END;  {pUpdateWindowInformation}
  887.   
  888.   
  889.   PROCEDURE pOurGetPicProc(
  890.     dataPtr: Ptr;
  891.     byteCount: Integer
  892.   );
  893.     VAR
  894.       longByteCount: Longint;
  895.       i: Integer;
  896.       retCode: OSErr;
  897.   BEGIN
  898.     longByteCount := Longint(byteCount);
  899.     retCode := FSRead(
  900.       vGlobalSpoolFileRefNumDuringOnePageUpdate,
  901.       longByteCount,
  902.       dataPtr
  903.     );
  904.     IF retCode <> noErr THEN
  905.       BEGIN
  906.         pFileErrorAlert(cAlertFileError, retCode, '???');
  907.         FOR i:=1 TO byteCount DO
  908.           BEGIN
  909.             dataPtr^ := -1;  { $FF, end of picture }
  910.             Longint(dataPtr) := Succ(Longint(dataPtr));
  911.           END;
  912.       END;
  913.   END;  {pOurGetPicProc}
  914.   
  915.   
  916.   PROCEDURE pUpdateWindowPageContents(
  917.     theWindow: WindowPtr;  {for convenience; must be current GrafPort}
  918.     vhWindowRelatedInfo: thWindowRelatedInfo;  {must be locked}
  919.     pageNumber: Integer;
  920.     needErasing: Boolean;
  921.     scalingForScreen: Boolean
  922.   );
  923.     LABEL
  924.       closeFile,
  925.       disposePicAndcloseFile;
  926.     VAR
  927.       spoolFileRefNum: Integer;
  928.       numberOfBytes: Longint;
  929.       handleToPagePicture: PicHandle;
  930.       stdProcs: QDProcs;
  931.       wePerformedTheCustomization: Boolean;
  932.       savedGetPicProc: QDPtr;
  933.       dstRect: Rect;
  934.       retCode: OSErr;
  935.   BEGIN
  936.     IF needErasing THEN
  937.       EraseRgn(theWindow^.visRgn);
  938.     
  939.     WITH vhWindowRelatedInfo^^ DO
  940.       BEGIN
  941.         retCode := FSOpen(rSFReply.fName, rSFReply.vRefNum, spoolFileRefNum);
  942.         IF retCode = noErr THEN
  943.           BEGIN
  944.             { Position to the start of the page. }
  945.             retCode := SetFPos(
  946.               spoolFileRefNum,
  947.               fsFromStart,
  948.               rSpoolFileHeader.pfPgDir.lPgPos[pageNumber]
  949.             );
  950.             IF retCode <> noErr THEN
  951.               BEGIN
  952.                 pFileErrorAlert(cAlertFileError, retCode, rSFReply.fName);
  953.                 GOTO closeFile;
  954.               END;
  955.               
  956.             numberOfBytes := Sizeof(Picture);
  957.             handleToPagePicture := PicHandle(NewHandle(numberOfBytes));
  958.             IF handleToPagePicture = NIL THEN
  959.               BEGIN
  960.                 pErrorAlert(cAlertNoMemoryForWindows);  {??? no mem. for update...}
  961.                 GOTO closeFile;
  962.               END;
  963.             retCode := FSRead(
  964.               spoolFileRefNum,
  965.               numberOfBytes,
  966.               Ptr(handleToPagePicture^)
  967.             );
  968.             IF retCode <> noErr THEN
  969.               BEGIN
  970.                 pFileErrorAlert(cAlertFileError, retCode, rSFReply.fName);
  971.                 GOTO disposePicAndcloseFile;
  972.               END;
  973.             
  974.             { Install a new picture retrieval procedure to read directly from disk. }
  975.             IF theWindow^.grafProcs = NIL THEN
  976.               BEGIN  { not customized yet }
  977.                 SetStdProcs(stdProcs);
  978.                 stdProcs.getPicProc := @pOurGetPicProc;
  979.                 theWindow^.grafProcs := @stdProcs;
  980.                 wePerformedTheCustomization := True;
  981.               END
  982.             ELSE
  983.               BEGIN  { already customized (by Printing Manager?) }
  984.                 savedGetPicProc := theWindow^.grafProcs^.getPicProc;
  985.                 theWindow^.grafProcs^.getPicProc := @pOurGetPicProc;
  986.                 wePerformedTheCustomization := False;
  987.               END;
  988.             
  989.             IF vHas128KROMs THEN
  990.               BEGIN
  991.                 SetFractEnable(rUsePrinterSpacing);
  992.                 SetFScaleDIsable(rDisableFontScaling);
  993.               END;
  994.               
  995.             vGlobalSpoolFileRefNumDuringOnePageUpdate := spoolFileRefNum;
  996.             { Draw the page picture from disk. }
  997.             IF scalingForScreen THEN
  998.               dstRect := rViewSize[cViewContents]
  999.             ELSE
  1000.               dstRect := rOriginalPageRect;
  1001.             DrawPicture(
  1002.               handleToPagePicture,
  1003.               dstRect
  1004.             );
  1005.             vGlobalSpoolFileRefNumDuringOnePageUpdate := 0;
  1006.             IF vHas128KROMs THEN
  1007.               BEGIN
  1008.                 SetFractEnable(False);
  1009.                 SetFScaleDIsable(False);
  1010.               END;
  1011.             
  1012.             IF wePerformedTheCustomization THEN
  1013.               theWindow^.grafProcs := NIL
  1014.             ELSE
  1015.               theWindow^.grafProcs^.getPicProc := savedGetPicProc;
  1016.           
  1017.           disposePicAndcloseFile:
  1018.             DisposHandle(Handle(handleToPagePicture));
  1019.           closeFile:
  1020.             retCode := FSClose(spoolFileRefNum);
  1021.           END  {IF opened successfully}
  1022.         ELSE
  1023.           BEGIN
  1024.             pFileErrorAlert(cAlertFileError, retCode, rSFReply.fName);
  1025.           END;
  1026.       END;  {WITH}
  1027.   END;  {pUpdateWindowPageContents}
  1028.   
  1029.   
  1030.   PROCEDURE pUpdateWindow { (forward) (resized: Boolean)} ;
  1031.     VAR
  1032.       theWindow: WindowPtr;
  1033.       vhWindowRelatedInfo: thWindowRelatedInfo;
  1034.       watchCursorHandle: CursHandle;
  1035.       vhHorizontalScroll: ControlHandle;
  1036.       vhVerticalScroll: ControlHandle;
  1037.       vScrollRect: Rect;
  1038.       pageNumberAsString: Str255;
  1039.       lastPageNumberAsString: Str255;
  1040.       
  1041.       saveClip: RgnHandle;
  1042.       docRect: Rect;
  1043.       pageRect: Rect;
  1044.       docRgn: RgnHandle;
  1045.       pageRgn: RgnHandle;
  1046.       theRgn: RgnHandle;
  1047.   BEGIN
  1048.     GetPort(theWindow);
  1049.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1050.     
  1051.     { Cursor as a wristwatch. }
  1052.     watchCursorHandle := GetCursor(watchCursor);
  1053.     IF watchCursorHandle <> NIL THEN
  1054.       SetCursor(watchCursorHandle^^);
  1055.         
  1056.     HLock(Handle(vhWindowRelatedInfo));
  1057.     
  1058.     
  1059.     {--- Update window "exteriors". }
  1060.     
  1061.     IF resized THEN
  1062.       BEGIN
  1063.         vhHorizontalScroll := vhWindowRelatedInfo^^.rHorizontalScrollControl;
  1064.         vhVerticalScroll := vhWindowRelatedInfo^^.rVerticalScrollControl;
  1065.         
  1066.         { HideControl invalidates the control area.  It will be }
  1067.         { redrawn, though, because everything is redrawn.  Thus we }
  1068.         { validate it back.  (MoveControl would call HideControl, }
  1069.         { if we didn't call it by ourselves.  Then we would not know }
  1070.         { the (automatically) invalidated rectangle.) }
  1071.         HideControl(vhHorizontalScroll);
  1072.         vScrollRect := vhHorizontalScroll^^.contrlRect;
  1073.         ValidRect(vScrollRect);
  1074.         HideControl(vhVerticalScroll);
  1075.         vScrollRect := vhVerticalScroll^^.contrlRect;
  1076.         ValidRect(vScrollRect);
  1077.         
  1078.         pCalcHorizontalScrollRect(theWindow, vScrollRect);
  1079.         SizeControl(vhHorizontalScroll, vScrollRect.right - vScrollRect.left, cMagicalWidthOfScrollBars);
  1080.         MoveControl(vhHorizontalScroll, vScrollRect.left, vScrollRect.top);
  1081.         ShowControl(vhHorizontalScroll);
  1082.  
  1083.         pCalcVerticalScrollRect(theWindow, vScrollRect);
  1084.         SizeControl(vhVerticalScroll, cMagicalWidthOfScrollBars, vScrollRect.bottom - vScrollRect.top);
  1085.         MoveControl(vhVerticalScroll, vScrollRect.left, vScrollRect.top);
  1086.         ShowControl(vhVerticalScroll);
  1087.         
  1088.         pSetScrollBarLimits(theWindow);
  1089.       END;
  1090.     
  1091.     DrawControls(theWindow);
  1092.     
  1093.     pCalcPageNumberRect(theWindow, vScrollRect);
  1094.     InsetRect(vScrollRect, 1, 1);
  1095.     EraseRect(vScrollRect);
  1096.     MoveTo(vScrollRect.left+1, vScrollRect.top+11);
  1097.     NumToString(
  1098.       Longint(vhWindowRelatedInfo^^.rPageNumber),
  1099.       pageNumberAsString
  1100.     );
  1101.     NumToString(
  1102.       Longint(vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages),
  1103.       lastPageNumberAsString
  1104.       );
  1105.     DrawString(
  1106.       fParametrizeSTR(
  1107.         cStringPage,  {from resource, but if not found, then here}
  1108.         'Page ^0 of ^1',
  1109.         pageNumberAsString,
  1110.         lastPageNumberAsString
  1111.       )
  1112.     );
  1113.     
  1114.     DrawGrowIcon(theWindow);
  1115.     
  1116.     
  1117.     {--- Update window contents. }
  1118.     
  1119.     SetOrigin(
  1120.       GetCtlValue(vhWindowRelatedInfo^^.rHorizontalScrollControl),
  1121.       GetCtlValue(vhWindowRelatedInfo^^.rVerticalScrollControl)
  1122.     );
  1123.     
  1124.     saveClip := NewRgn;
  1125.     IF saveClip <> NIL THEN
  1126.       BEGIN
  1127.         GetClip(saveClip);
  1128.         pCalcDocumentRect(theWindow, docRect);
  1129.         ClipRect(docRect);  {to save already drawn scroll bars}
  1130.         docRgn := NewRgn;
  1131.         IF docRgn <> NIL THEN
  1132.           GetClip(docRgn);
  1133.       END;  {IF saveClip could be allocated }
  1134.     
  1135.     CASE vhWindowRelatedInfo^^.rViewMenuSelectionForThisWindow OF
  1136.       cViewContents:
  1137.         BEGIN
  1138.           { Draw grey around actual document. }
  1139.           { (=remove current page drawing area from window clip (=doc area)). }
  1140.           pageRect := vhWindowRelatedInfo^^.rViewSize[cViewContents];
  1141.           pageRgn := NewRgn;
  1142.           RectRgn(
  1143.             pageRgn,
  1144.             pageRect
  1145.           );
  1146.           
  1147.           theRgn := NewRgn;
  1148.           DiffRgn(docRgn, pageRgn, theRgn);
  1149.           
  1150.           { Grey background. }
  1151.           PenPat(gray);
  1152.           PaintRgn(theRgn);  {background}
  1153.           PenPat(black);
  1154.           
  1155.           { Drop shadow: frame page; don't draw to top left; }
  1156.           InsetRect(pageRect, -1, -1);
  1157.           FrameRect(pageRect);
  1158.           InsetRect(pageRect, 1, 1);
  1159.           SetClip(theRgn);
  1160.           OffsetRect(pageRect, 2, 2);
  1161.           PenSize(2, 2);
  1162.           FrameRect(pageRect);
  1163.           PenSize(1, 1);
  1164.           
  1165.           { Page drawing. }
  1166.           SectRgn(
  1167.             docRgn,
  1168.             pageRgn,
  1169.             theRgn
  1170.           );  {to save everything but page}
  1171.           SetClip(theRgn);
  1172.           pUpdateWindowPageContents(
  1173.             theWindow,
  1174.             vhWindowRelatedInfo,
  1175.             vhWindowRelatedInfo^^.rPageNumber,
  1176.             {needErasing=>} True,
  1177.             {scalingForScreen=>} True
  1178.           );
  1179.           
  1180.           DisposeRgn(theRgn);
  1181.           DisposeRgn(pageRgn);
  1182.         END;
  1183.       
  1184.       OTHERWISE
  1185.         pUpdateWindowInformation(
  1186.           theWindow,
  1187.           vhWindowRelatedInfo,
  1188.           True  {needErasing}
  1189.         );
  1190.     END;  {CASE}
  1191.         
  1192.     IF saveClip <> NIL THEN
  1193.       BEGIN
  1194.         SetClip(saveClip);
  1195.         DisposeRgn(saveClip);
  1196.         IF docRgn <> NIL THEN
  1197.           DisposeRgn(docRgn);
  1198.       END;  {IF saveClip could be allocated }
  1199.  
  1200.     SetOrigin(0, 0);
  1201.     
  1202.     
  1203.     {---}
  1204.     
  1205.     HUnlock(Handle(vhWindowRelatedInfo));
  1206.  
  1207.     { Cursor as an arrow. }
  1208.     SetCursor(arrow);
  1209.   END;  {pUpdateWindow}
  1210.  
  1211.  
  1212.   PROCEDURE pChangeViewMenuAccordingToWindow {(theWindow: WindowPtr)} ;
  1213.     VAR
  1214.       vhWindowRelatedInfo: thWindowRelatedInfo;
  1215.       theItem: Integer;
  1216.       i: Integer;
  1217.   BEGIN
  1218.     IF theWindow = NIL THEN
  1219.       theItem := vViewMenuSelectionDefault
  1220.     ELSE
  1221.       BEGIN  {get the viewing method of a window}
  1222.         vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1223.         theItem := vhWindowRelatedInfo^^.rViewMenuSelectionForThisWindow;
  1224.       END;
  1225.     
  1226.     FOR i:= cViewInformation TO cViewContents DO 
  1227.       CheckItem(vMenu[eView], i, (i=theItem));
  1228.   END;  {pChangeViewMenuAccordingToWindow}
  1229.   
  1230.   
  1231.   PROCEDURE pChangeSettingsMenuAccordingToWindow {(theWindow: WindowPtr)} ;
  1232.     VAR
  1233.       vhWindowRelatedInfo: thWindowRelatedInfo;
  1234.       usePrinterSpacing: Boolean;
  1235.       disableFontScaling: Boolean;
  1236.   BEGIN
  1237.     IF theWindow = NIL THEN
  1238.       BEGIN
  1239.         usePrinterSpacing := vSettingsUsePrinterSpacing;
  1240.         disableFontScaling := vSettingsDisableFontScaling;
  1241.       END
  1242.     ELSE
  1243.       BEGIN  {get the font settings for this window}
  1244.         vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1245.         usePrinterSpacing := vhWindowRelatedInfo^^.rUsePrinterSpacing;
  1246.         disableFontScaling := vhWindowRelatedInfo^^.rDisableFontScaling;
  1247.       END;
  1248.     
  1249.     CheckItem(vMenu[eSettings], cSettingsUsePrinterSpacing, usePrinterSpacing);
  1250.     CheckItem(vMenu[eSettings], cSettingsDisableFontScaling, disableFontScaling);
  1251.   END;  {pChangeSettingsMenuAccordingToWindow}
  1252.   
  1253.   
  1254.   PROCEDURE pNormalizePageNumberAndAdjustPageMenu(
  1255.     vhWindowRelatedInfo: thWindowRelatedInfo
  1256.   );
  1257.     VAR
  1258.       thePageNumber: Integer;
  1259.   BEGIN
  1260.     thePageNumber := vhWindowRelatedInfo^^.rPageNumber;
  1261.     
  1262.     IF vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages <= 1 THEN
  1263.       BEGIN
  1264.         thePageNumber := 1;
  1265.         DisableItem(vMenu[ePage], cPagePrevious);
  1266.         DisableItem(vMenu[ePage], cPageNext);
  1267.         DisableItem(vMenu[ePage], cPageFirst);
  1268.         DisableItem(vMenu[ePage], cPageLast);
  1269.       END
  1270.     ELSE IF thePageNumber <= 1 THEN
  1271.       BEGIN
  1272.         thePageNumber := 1;
  1273.         DisableItem(vMenu[ePage], cPagePrevious);
  1274.         EnableItem(vMenu[ePage], cPageNext);
  1275.         DisableItem(vMenu[ePage], cPageFirst);
  1276.         EnableItem(vMenu[ePage], cPageLast);
  1277.       END
  1278.     ELSE IF thePageNumber >=
  1279.               vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages
  1280.     THEN
  1281.       BEGIN
  1282.         thePageNumber := vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages;
  1283.         EnableItem(vMenu[ePage], cPagePrevious);
  1284.         DisableItem(vMenu[ePage], cPageNext);
  1285.         EnableItem(vMenu[ePage], cPageFirst);
  1286.         DisableItem(vMenu[ePage], cPageLast);
  1287.       END
  1288.     ELSE
  1289.       BEGIN
  1290.         {thePageNumber is ok}
  1291.         EnableItem(vMenu[ePage], cPageNext);
  1292.         EnableItem(vMenu[ePage], cPagePrevious);
  1293.         EnableItem(vMenu[ePage], cPageFirst);
  1294.         EnableItem(vMenu[ePage], cPageLast);
  1295.       END;
  1296.     
  1297.     vhWindowRelatedInfo^^.rPageNumber := thePageNumber;
  1298.   END;  {pNormalizePageNumberAndAdjustPageMenu}
  1299.   
  1300.  
  1301.   PROCEDURE pChangePageMenuAccordingToWindow(theWindow: WindowPtr);
  1302.     VAR
  1303.       vhWindowRelatedInfo: thWindowRelatedInfo;
  1304.       pageNumber,
  1305.       lastPageNumber: Integer;
  1306.       pageNumberAsString,
  1307.       lastPageNumberAsString: Str255;
  1308.   BEGIN
  1309.     IF theWindow = NIL THEN
  1310.       BEGIN
  1311.         pageNumber := 1;
  1312.         lastPageNumber := 1;
  1313.       END
  1314.     ELSE
  1315.       BEGIN  {get the font settings for this window}
  1316.         vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1317.         pNormalizePageNumberAndAdjustPageMenu(vhWindowRelatedInfo);
  1318.         pageNumber := vhWindowRelatedInfo^^.rPageNumber;
  1319.         lastPageNumber := vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages;
  1320.       END;
  1321.     NumToString(pageNumber, pageNumberAsString);
  1322.     NumToString(lastPageNumber, lastPageNumberAsString);
  1323.     SetItem(
  1324.       vMenu[ePage],
  1325.       cPagePageNumberItem,
  1326.       fParametrizeSTR(
  1327.         cStringPage,  {from resource, but if not found, then here}
  1328.         'Page ^0 of ^1',
  1329.         pageNumberAsString,
  1330.         lastPageNumberAsString
  1331.       )
  1332.     );
  1333.     
  1334.     { Seems to be unnecessary to invalidate page number rectangle }
  1335.     { to redraw it. }
  1336.   END;  {pChangePageMenuAccordingToWindow}
  1337.   
  1338.   
  1339.   FUNCTION fNotExistingOrNotOurs(theWindow: WindowPtr) : Boolean;
  1340.   BEGIN
  1341.     IF theWindow = NIL THEN
  1342.       fNotExistingOrNotOurs := True
  1343.     ELSE IF WindowPeek(theWindow)^.windowKind <> userKind THEN
  1344.       fNotExistingOrNotOurs := True
  1345.     ELSE
  1346.       fNotExistingOrNotOurs := False;
  1347.   END;  {fNotExistingOrNotOurs}
  1348.   
  1349.   
  1350.   PROCEDURE pActivateWindow(active: Boolean);
  1351.     VAR
  1352.       savePort: WindowPtr;
  1353.       theWindow: WindowPtr;
  1354.       
  1355.       aControl: ControlHandle;
  1356.   BEGIN
  1357.     GetPort(savePort);
  1358.     theWindow := savePort;
  1359.     IF (NOT active) AND (theWindow = FrontWindow) THEN
  1360.       BEGIN
  1361.         { A truly horrendous kludge to overcome a TransSkel deficiency: }
  1362.         { When windows are deactivated, the port is not set. }
  1363.         { Thus we "back" one window.  Fails miserably if for some reason }
  1364.         { the deactivated window was not frontmost. }
  1365.         theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);  {back one}
  1366.         IF fNotExistingOrNotOurs(theWindow) THEN
  1367.           Exit;  {no back window}
  1368.         SetPort(theWindow);  {to make for instance ValidRect work}
  1369.       END;
  1370.     
  1371.     IF active THEN
  1372.       BEGIN
  1373.         pChangeViewMenuAccordingToWindow(theWindow);
  1374.         pChangeSettingsMenuAccordingToWindow(theWindow);
  1375.         pChangePageMenuAccordingToWindow(theWindow);
  1376.       END;
  1377.     
  1378.     { Scroll bars etc. }
  1379.     aControl := WindowPeek(theWindow)^.controlList;
  1380.     WHILE aControl <> NIL DO
  1381.       BEGIN
  1382.         IF active THEN
  1383.           ShowControl(aControl)
  1384.         ELSE
  1385.           BEGIN
  1386.             HideControl(aControl);
  1387.             { HideControl redraws the blank scroll bar. }
  1388.             HLock(Handle(aControl));
  1389.             ValidRect(aControl^^.contrlRect);  {shouldn't it be """visRgn""" of control??}
  1390.             HUnlock(Handle(aControl));
  1391.           END;
  1392.         
  1393.         aControl := aControl^^.nextControl;
  1394.       END;  {WHILE}
  1395.     
  1396.     DrawGrowIcon(theWindow);
  1397.     
  1398.     SetPort(savePort);
  1399.     { End of window appearance operations, start of other things. }
  1400.     
  1401.     { Inactivate events come before activate events: }
  1402.     { thus menus can be disabled/enabled.  Primary for desk acc. windows. }
  1403.     IF active THEN
  1404.       BEGIN
  1405.         EnableItem(vMenu[eFile], cFileClose);
  1406.         EnableItem(vMenu[eFile], cFileCloseAll);
  1407.         EnableItem(vMenu[eFile], cFilePageSetup);
  1408.         EnableItem(vMenu[eFile], cFilePageSetupAll);
  1409.         EnableItem(vMenu[eFile], cFilePrint);
  1410.         EnableItem(vMenu[eFile], cFilePrintAll);
  1411.         
  1412.         DisableItem(vMenu[eEdit], cEditUndo);
  1413.         DisableItem(vMenu[eEdit], cEditCut);
  1414.         DisableItem(vMenu[eEdit], cEditCopy);
  1415.         DisableItem(vMenu[eEdit], cEditPaste);
  1416.         DisableItem(vMenu[eEdit], cEditClear);
  1417.         
  1418.         EnableItem(vMenu[eView], cViewInformation);
  1419.         EnableItem(vMenu[eView], cViewContents);
  1420.         EnableItem(vMenu[eView], cViewScalePreview);
  1421.         
  1422.         EnableItem(vMenu[eSettings], cSettingsUsePrinterSpacing);
  1423.         EnableItem(vMenu[eSettings], cSettingsDisableFontScaling);
  1424.         
  1425.         { next, previous, first, last are enabled in change page menu above}
  1426.         EnableItem(vMenu[ePage], cPageGotoPage);
  1427.       END
  1428.     ELSE
  1429.       BEGIN
  1430.         DisableItem(vMenu[eFile], cFileClose);
  1431.         DisableItem(vMenu[eFile], cFileCloseAll);
  1432.         DisableItem(vMenu[eFile], cFilePageSetup);
  1433.         DisableItem(vMenu[eFile], cFilePageSetupAll);
  1434.         DisableItem(vMenu[eFile], cFilePrint);
  1435.         DisableItem(vMenu[eFile], cFilePrintAll);
  1436.         
  1437.         EnableItem(vMenu[eEdit], cEditUndo);
  1438.         EnableItem(vMenu[eEdit], cEditCut);
  1439.         EnableItem(vMenu[eEdit], cEditCopy);
  1440.         EnableItem(vMenu[eEdit], cEditPaste);
  1441.         EnableItem(vMenu[eEdit], cEditClear);
  1442.         
  1443.         DisableItem(vMenu[eView], cViewInformation);
  1444.         DisableItem(vMenu[eView], cViewContents);
  1445.         DisableItem(vMenu[eView], cViewScalePreview);
  1446.         
  1447.         DisableItem(vMenu[eSettings], cSettingsUsePrinterSpacing);
  1448.         DisableItem(vMenu[eSettings], cSettingsDisableFontScaling);
  1449.         
  1450.         DisableItem(vMenu[ePage], cPageNext);
  1451.         DisableItem(vMenu[ePage], cPagePrevious);
  1452.         DisableItem(vMenu[ePage], cPageFirst);
  1453.         DisableItem(vMenu[ePage], cPageLast);
  1454.         DisableItem(vMenu[ePage], cPageGotoPage);
  1455.       END;
  1456.   END;  {pActivateWindow}
  1457.  
  1458.  
  1459.   PROCEDURE pCallTransSkelToRemoveWindow(theWindow: WindowPtr);
  1460.   BEGIN
  1461.     SkelRmveWind(theWindow);
  1462.     vNumberOfOurOpenWindows := vNumberOfOurOpenWindows - 1;
  1463.     IF vNumberOfOurOpenWindows <= 0 THEN
  1464.       pMenusToState(eNoOurWindowsOpen);
  1465.   END;  {pCallTransSkelToRemoveWindow}
  1466.   
  1467.   
  1468.   PROCEDURE pCloseWindow;  {for TransSkel}
  1469.     VAR
  1470.       theWindow: WindowPtr;
  1471.   BEGIN
  1472.     GetPort(theWindow);
  1473.     IF fNotExistingOrNotOurs(theWindow) THEN
  1474.       Exit;
  1475.     
  1476.     pCallTransSkelToRemoveWindow(theWindow);
  1477.   END;  {pCloseWindow}
  1478.  
  1479.  
  1480.   PROCEDURE pDoClose;  {for File menu}
  1481.     VAR
  1482.       theWindow: WindowPtr;
  1483.   BEGIN
  1484.     theWindow := FrontWindow;
  1485.       {For symmetry we shoud call GetPort,}
  1486.       {but FrontWindow tells us when there are none of them.}
  1487.     IF fNotExistingOrNotOurs(theWindow) THEN
  1488.       Exit;
  1489.     
  1490.     pCallTransSkelToRemoveWindow(theWindow);
  1491.   END;  {pDoClose}
  1492.  
  1493.  
  1494.   PROCEDURE pDoCloseAll;
  1495.     VAR
  1496.       theWindow: WindowPtr;
  1497.   BEGIN
  1498.     theWindow := FrontWindow;
  1499.     WHILE theWindow <> NIL DO
  1500.       BEGIN
  1501.         IF WindowPeek(theWindow)^.windowKind = userKind THEN
  1502.           pCallTransSkelToRemoveWindow(theWindow);
  1503.         theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1504.       END;  {WHILE}
  1505.   END;  {pDoCloseAll}
  1506.  
  1507.  
  1508.   PROCEDURE pOpenWindowByName(
  1509.     theName: Str255;
  1510.     theVRefNum: Integer
  1511.   );
  1512.     VAR
  1513.       theWindow: WindowPtr;
  1514.       vSFReply: SFReply;
  1515.   BEGIN
  1516.    { Set the SFReply just as if a SFGetFile would have set.}
  1517.     vSFReply.fName := theName;
  1518.     vSFReply.vRefNum := theVRefNum;
  1519.     vSFReply.good := True;
  1520.       
  1521.     IF NOT fCreateWindow(theWindow, vSFReply) THEN
  1522.       Exit;
  1523.     
  1524.     IF NOT SkelWindow(
  1525.       theWindow,
  1526.       @pMouseInWindow,
  1527.       NIL,  {no keyboard handling}
  1528.       @pUpdateWindow,
  1529.       @pActivateWindow,
  1530.       @pCloseWindow,
  1531.       @pDisposeAllStructuresRelatedToCurrentWindow,
  1532.       NIL,  {no idle procedure for this window}
  1533.       True  {idle procedure need to be called only when this window is topmost}
  1534.     )
  1535.     THEN
  1536.       BEGIN
  1537.         pErrorAlert(cAlertNoMemoryForWindows);
  1538.         pDisposeAllStructuresRelatedToThisWindow(theWindow);
  1539.         DisposeWindow(theWindow);
  1540.         Exit;
  1541.       END;
  1542.   END;  {pOpenWindowByName}
  1543.  
  1544.  
  1545.   PROCEDURE pOpenWindowByAskingUserTheName;
  1546.     VAR
  1547.       theWindow: WindowPtr;
  1548.       where: Point;
  1549.       prompt: Str255;
  1550.       allowedFileTypes: SFTypeList;
  1551.       vSFReply: SFReply;
  1552.   BEGIN
  1553.     where.v := 70;
  1554.     where.h := 70;
  1555.     prompt := '';
  1556.     allowedFileTypes[0] := 'PFIL';
  1557.     SFGetFile(
  1558.       where,
  1559.       prompt,
  1560.       NIL,  {fileFilter}
  1561.       1,  {one allowed file type}
  1562.       allowedFileTypes,
  1563.       NIL,  {dlgHook}
  1564.       vSFReply
  1565.     );
  1566.     
  1567.     IF NOT vSFReply.good THEN
  1568.       Exit;
  1569.       
  1570.     IF NOT fCreateWindow(theWindow, vSFReply) THEN
  1571.       Exit;
  1572.     
  1573.     IF NOT SkelWindow(
  1574.       theWindow,
  1575.       @pMouseInWindow,  {no mouse handling}
  1576.       NIL,  {no keyboard handling}
  1577.       @pUpdateWindow,
  1578.       @pActivateWindow,
  1579.       @pCloseWindow,
  1580.       @pDisposeAllStructuresRelatedToCurrentWindow,
  1581.       NIL,  {no idle procedure for this window}
  1582.       True  {idle procedure need to be called only when this window is topmost}
  1583.     )
  1584.     THEN
  1585.       BEGIN
  1586.         pErrorAlert(cAlertNoMemoryForWindows);
  1587.         pDisposeAllStructuresRelatedToThisWindow(theWindow);
  1588.         DisposeWindow(theWindow);
  1589.         Exit;
  1590.       END;
  1591.   END;  {pOpenWindowByAskingUserTheName}
  1592.   
  1593.   
  1594.   FUNCTION fOurPageSetup(theWindow: WindowPtr) : Boolean;
  1595.     VAR
  1596.       vhWindowRelatedInfo: thWindowRelatedInfo;
  1597.       wasItChanged: Boolean;
  1598.       doIt: Boolean;
  1599.   BEGIN
  1600.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1601.     
  1602.     { From Tech Note 161: }
  1603.     PrOpen;
  1604.     IF PrError = noErr THEN 
  1605.       BEGIN
  1606.         wasItChanged := PrValidate(THPrint(vhWindowRelatedInfo));
  1607.         doIt := PrStlDialog(THPrint(vhWindowRelatedInfo));
  1608.         IF PrError <> noErr THEN
  1609.           pPrintErrorAlert(cAlertPrintError, PrError)
  1610.         ELSE
  1611.           ;  {do whatever you need to}
  1612.       END
  1613.     ELSE
  1614.       pPrintErrorAlert(cAlertPrintError, PrError);
  1615.     PrClose;
  1616.     
  1617.     fOurPageSetup := doIt AND (PrError = noErr);
  1618.   END;  {fOurPageSetup}
  1619.  
  1620.  
  1621.   FUNCTION fOurPrintWindow(
  1622.     theWindow: WindowPtr;
  1623.     doYouWishToPresentJobDialog: Boolean
  1624.   ) : Boolean;
  1625.     LABEL
  1626.       closeDriver;
  1627.     VAR
  1628.       vhWindowRelatedInfo: thWindowRelatedInfo;
  1629.       savePort: GrafPtr;
  1630.       wasItChanged: Boolean;
  1631.       doIt: Boolean;
  1632.       printingGrafPort: TPPrPort;
  1633.       myFirst,
  1634.       myLast,
  1635.       pageNumber: Integer;
  1636.       dummyStatusRecord: TPrStatus;
  1637.   BEGIN
  1638.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1639.  
  1640.     GetPort(savePort);
  1641.     
  1642.     PrOpen;  {open up printer resource file}
  1643.     IF PrError <> noErr THEN
  1644.       BEGIN
  1645.         pPrintErrorAlert(cAlertPrintError, PrError);
  1646.         doIt := False;
  1647.         GOTO closeDriver;
  1648.       END;
  1649.       
  1650.     wasItChanged := PrValidate(THPrint(vhWindowRelatedInfo));
  1651.     IF doYouWishToPresentJobDialog THEN
  1652.       BEGIN
  1653.         doIt := PrJobDialog(THPrint(vhWindowRelatedInfo));
  1654.         IF NOT doIt THEN
  1655.           GOTO closeDriver;
  1656.       END
  1657.     ELSE
  1658.       doIt := True;
  1659.  
  1660.     printingGrafPort := PrOpenDoc(  { open printing grafPort }
  1661.       THPrint(vhWindowRelatedInfo),
  1662.       NIL,
  1663.       NIL
  1664.     );
  1665.     myFirst := THPrint(vhWindowRelatedInfo)^^.prJob.iFstPage;
  1666.     myLast := THPrint(vhWindowRelatedInfo)^^.prJob.iLstPage;
  1667.     IF myLast > vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages THEN
  1668.       myLast := vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages;
  1669.     THPrint(vhWindowRelatedInfo)^^.prJob.iFstPage := 1;
  1670.     THPrint(vhWindowRelatedInfo)^^.prJob.iLstPage := iPrPgMax;
  1671.     FOR pageNumber:=myFirst TO myLast DO  {page loop}
  1672.       IF PrError = noErr THEN
  1673.        BEGIN
  1674.          PrOpenPage(printingGrafPort, NIL);
  1675.          IF PrError = noErr THEN
  1676.            BEGIN
  1677.              HLock(Handle(vhWindowRelatedInfo));
  1678.              pUpdateWindowPageContents(
  1679.                GrafPtr(printingGrafPort),
  1680.                vhWindowRelatedInfo,
  1681.                pageNumber,
  1682.                {needErasing=>} False,  {not on paper}
  1683.                {scalingForScreen=>} False  {always original size}
  1684.              );  {draw page with QuickDraw}
  1685.              HUnlock(Handle(vhWindowRelatedInfo));
  1686.            END;
  1687.          PrClosePage(printingGrafPort);
  1688.        END;
  1689.     PrCloseDoc(printingGrafPort);
  1690.     
  1691.     IF (THPrint(vhWindowRelatedInfo)^^.prJob.bJDocLoop = bSpoolLoop)
  1692.          AND (PrError = noErr) THEN
  1693.       BEGIN
  1694.         { MySwapOutProc;  swap out code and data, if necessary }
  1695.         PrPicFile(
  1696.           THPrint(vhWindowRelatedInfo),
  1697.           NIL,
  1698.           NIL,
  1699.           NIL,
  1700.           dummyStatusRecord
  1701.         );
  1702.       END;
  1703.     IF PrError <> noErr THEN
  1704.       pPrintErrorAlert(cAlertPrintError, PrError);
  1705.     
  1706.   closeDriver:
  1707.     PrClose;
  1708.     
  1709.     SetPort(savePort);
  1710.     
  1711.     fOurPrintWindow := doIt;
  1712.   END;  {fOurPrintWindow}
  1713.  
  1714.  
  1715.   PROCEDURE pCopyThePrintRecord(source, destination: thWindowRelatedInfo);
  1716.   BEGIN
  1717.     destination^^.rSpoolFileHeader.Print := source^^.rSpoolFileHeader.Print;
  1718.   END;  {pCopyThePrintRecord}
  1719.   
  1720.   
  1721.   PROCEDURE pDoPageSetupAll;
  1722.     VAR
  1723.       theWindow: WindowPtr;
  1724.       doIt: Boolean;
  1725.   BEGIN
  1726.     theWindow := FrontWindow;
  1727.     IF fNotExistingOrNotOurs(theWindow) THEN
  1728.       Exit;
  1729.     
  1730.     doIt := fOurPageSetup(theWindow);
  1731.     IF doIt THEN
  1732.       BEGIN
  1733.         theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1734.         WHILE theWindow <> NIL DO
  1735.           BEGIN
  1736.             IF WindowPeek(theWindow)^.windowKind = userKind THEN
  1737.               pCopyThePrintRecord(
  1738.                 thWindowRelatedInfo(GetWRefCon(FrontWindow)),
  1739.                 thWindowRelatedInfo(GetWRefCon(theWindow))
  1740.               );
  1741.             theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1742.           END;  {WHILE}
  1743.       END;  {IF OK clicked}
  1744.   END;  {pDoPageSetupAll}
  1745.  
  1746.  
  1747.   PROCEDURE pDoPrintAll;
  1748.     VAR
  1749.       theWindow: WindowPtr;
  1750.       doIt: Boolean;
  1751.   BEGIN
  1752.     theWindow := FrontWindow;
  1753.     IF fNotExistingOrNotOurs(theWindow) THEN
  1754.       Exit;
  1755.     
  1756.     doIt := fOurPrintWindow(theWindow,  {job dialog=>} True);
  1757.     IF doIt THEN
  1758.       BEGIN
  1759.         theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1760.         WHILE theWindow <> NIL DO
  1761.           BEGIN
  1762.             IF WindowPeek(theWindow)^.windowKind = userKind THEN
  1763.               BEGIN
  1764.                 BEGIN  { use Job Merge }
  1765.                   PrOpen;
  1766.                   IF PrError = noErr THEN 
  1767.                     BEGIN
  1768.                       PrJobMerge(
  1769.                         THPrint(GetWRefCon(FrontWindow)),
  1770.                         THPrint(GetWRefCon(theWindow))
  1771.                       );
  1772.                     END
  1773.                   ELSE
  1774.                     pPrintErrorAlert(cAlertPrintError, PrError);
  1775.                   PrClose;
  1776.                 END;  { use Job Merge }
  1777.  
  1778.                 doIt := fOurPrintWindow(theWindow,  {job dialog=>} False);
  1779.               END;  {IF our window}
  1780.             theWindow := WindowPtr(WindowPeek(theWindow)^.nextWindow);
  1781.           END;  {WHILE}
  1782.       END;  {IF OK clicked}
  1783.   END;  {pDoPrintAll}
  1784.  
  1785.  
  1786.   PROCEDURE pDoFileMenu(theItem: Integer);
  1787.     VAR
  1788.       theWindow: WindowPtr;
  1789.       doIt: Boolean;
  1790.   BEGIN
  1791.     CASE theItem OF
  1792.       cFileOpen:
  1793.         pOpenWindowByAskingUserTheName;
  1794.         
  1795.       cFileClose:
  1796.         pDoClose;
  1797.         
  1798.       cFileCloseAll:
  1799.         pDoCloseAll;
  1800.         
  1801.       cFilePageSetup:
  1802.         BEGIN
  1803.           theWindow := FrontWindow;
  1804.           IF fNotExistingOrNotOurs(theWindow) THEN
  1805.             Exit;
  1806.           
  1807.           doIt := fOurPageSetup(theWindow);
  1808.         END;  {CASE page setup}
  1809.         
  1810.       cFilePageSetupAll:
  1811.         pDoPageSetupAll;
  1812.         
  1813.       cFilePrint:
  1814.         BEGIN
  1815.           theWindow := FrontWindow;
  1816.           IF fNotExistingOrNotOurs(theWindow) THEN
  1817.             Exit;
  1818.           
  1819.           doIt := fOurPrintWindow(theWindow, True {job dialog} );
  1820.         END;  {CASE print}
  1821.         
  1822.       cFilePrintAll:
  1823.         pDoPrintAll;
  1824.         
  1825.       OTHERWISE
  1826.         SkelWhoa;
  1827.     END;  {CASE}
  1828.   END;  {pDoFileMenu}
  1829.  
  1830.  
  1831.   PROCEDURE pDoEditMenu(theItem: Integer);
  1832.   BEGIN
  1833.   END;  {pDoEditMenu}
  1834.   
  1835.   
  1836.   PROCEDURE pFrameButton(
  1837.     theDialog: DialogPtr;
  1838.     theItem: Integer
  1839.   );
  1840.     VAR
  1841.       savePort: GrafPtr;
  1842.       itemType: Integer;
  1843.       itemHandle: Handle;
  1844.       itemBBox: Rect;
  1845.       integerAsString: Str255;
  1846.       integerAsLongint: Longint;
  1847.   BEGIN
  1848.     GetPort(savePort);
  1849.     SetPort(theDialog);
  1850.     GetDItem(theDialog, theItem, itemType, itemHandle, itemBBox);
  1851.     PenSize(3, 3);
  1852.     InsetRect(itemBBox, -4, -4);
  1853.     FrameRoundRect(itemBBox, 16, 16);
  1854.     SetPort(savePort);
  1855.   END;  {pFrameButton}
  1856.   
  1857.   
  1858.   PROCEDURE pSetTextDITFromInteger(
  1859.     theDialog: DialogPtr;
  1860.     theItem: Integer;
  1861.     theInteger: Integer
  1862.   );
  1863.     VAR
  1864.       itemType: Integer;
  1865.       itemHandle: Handle;
  1866.       itemBBox: Rect;
  1867.       integerAsString: Str255;
  1868.   BEGIN
  1869.     GetDItem(theDialog, theItem, itemType, itemHandle, itemBBox);
  1870.     itemType := itemType MOD itemDisable;
  1871.     IF (itemType = statText) OR (itemType = editText) THEN
  1872.       BEGIN
  1873.         NumToString(theInteger, integerAsString);
  1874.         SetIText(itemHandle, integerAsString);
  1875.       END;
  1876.   END;  {pSetTextDITFromInteger}
  1877.   
  1878.   
  1879.   FUNCTION fGetTextDITAsInteger(
  1880.     theDialog: DialogPtr;
  1881.     theItem: Integer
  1882.   ) : Integer;
  1883.     VAR
  1884.       itemType: Integer;
  1885.       itemHandle: Handle;
  1886.       itemBBox: Rect;
  1887.       integerAsString: Str255;
  1888.       integerAsLongint: Longint;
  1889.   BEGIN
  1890.     GetDItem(theDialog, theItem, itemType, itemHandle, itemBBox);
  1891.     itemType := itemType MOD itemDisable;
  1892.     IF (itemType = statText) OR (itemType = editText) THEN
  1893.       BEGIN
  1894.         GetIText(itemHandle, integerAsString);
  1895.         StringToNum(integerAsString, integerAsLongint);
  1896.         fGetTextDITAsInteger := integerAsLongint;
  1897.       END
  1898.     ELSE
  1899.       fGetTextDITAsInteger := 0;
  1900.   END;  {fGetTextDITAsInteger}
  1901.   
  1902.   
  1903.   PROCEDURE pDoViewMenu(theItem: Integer);
  1904.   
  1905.     VAR
  1906.       theWindow: WindowPtr;
  1907.       vhWindowRelatedInfo: thWindowRelatedInfo;
  1908.       i: Integer;
  1909.       theDialog: DialogPtr;
  1910.       itemHit: Integer;
  1911.       
  1912.     FUNCTION fCheckAndCorrected(VAR percentage: Integer) : Boolean;
  1913.       VAR
  1914.         percentageAsString: Str255;
  1915.         explanation: Str255;
  1916.         buttonClicked: Integer;
  1917.     BEGIN
  1918.       buttonClicked := cOkButton;
  1919.       NumToString(Longint(percentage), percentageAsString);
  1920.       IF percentage < 5 THEN
  1921.         BEGIN
  1922.           explanation := fParametrizeSTR(
  1923.             cStringUnderMinimum,
  1924.             'The value ╥^0╙ is replaced by the smallest allowed minimum of 5%.',
  1925.             percentageAsString,
  1926.             ''
  1927.           );
  1928.           ParamText(explanation, '', '', '');
  1929.           buttonClicked := Alert(cAlertScalingPercentageOutOfBounds, NIL);
  1930.           IF buttonClicked = cOkButton THEN
  1931.             percentage := 5;
  1932.         END
  1933.       ELSE IF percentage >3200 THEN
  1934.         BEGIN
  1935.           explanation := fParametrizeSTR(
  1936.             cStringOverMaximum,
  1937.             'The value ╥^0╙ is replaced by the largest allowed maximum of 3200%.',
  1938.             percentageAsString,
  1939.             ''
  1940.           );
  1941.           ParamText(explanation, '', '', '');
  1942.           buttonClicked := Alert(cAlertScalingPercentageOutOfBounds, NIL);
  1943.           IF buttonClicked = cOkButton THEN
  1944.             percentage := 3200;
  1945.         END
  1946.       ELSE
  1947.         ResetAlrtStage;  {reward for right answer :-) }
  1948.       
  1949.       fCheckAndCorrected := (buttonClicked = cOkButton);
  1950.     END;  {fCheckAndCorrected}
  1951.     
  1952.   BEGIN
  1953.     theWindow := FrontWindow;
  1954.     CASE theItem OF
  1955.       cViewInformation,
  1956.       cViewContents:
  1957.         BEGIN
  1958.           IF fNotExistingOrNotOurs(theWindow) THEN
  1959.             vViewMenuSelectionDefault := theItem
  1960.           ELSE
  1961.             BEGIN  {set the viewing method of a window}
  1962.               vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1963.               vhWindowRelatedInfo^^.rViewMenuSelectionForThisWindow := theItem;
  1964.               pSetScrollBarLimits(theWindow);
  1965.               pInvalidateAllOfWindow(theWindow);
  1966.             END;
  1967.           
  1968.           FOR i:= cViewInformation TO cViewContents DO 
  1969.             CheckItem(vMenu[eView], i, (i=theItem));
  1970.         END;
  1971.       
  1972.       cViewScalePreview:
  1973.         BEGIN  {set the scaling percentage of a window}
  1974.           theDialog := GetNewDialog(cDialogScalePreview, NIL, WindowPtr(-1));
  1975.           IF theDialog <> NIL THEN
  1976.             BEGIN
  1977.               pFrameButton(theDialog, cOkButton);
  1978.               IF fNotExistingOrNotOurs(theWindow) THEN
  1979.                 pSetTextDITFromInteger(  {from global defaults}
  1980.                   theDialog,
  1981.                   cDITScalePercentage,
  1982.                   vViewScalePercentageDefault
  1983.                 )
  1984.               ELSE
  1985.                 BEGIN
  1986.                   vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  1987.                   pSetTextDITFromInteger(  {from window}
  1988.                     theDialog,
  1989.                     cDITScalePercentage,
  1990.                     vhWindowRelatedInfo^^.rViewScalePreviewPercentage
  1991.                   )
  1992.                 END;
  1993.               SelIText(theDialog, cDITScalePercentage, 0, 32767);  {preselect it}
  1994.               ModalDialog( {filterProc=>} NIL, itemHit);
  1995.               
  1996.               IF itemHit = cOkButton THEN
  1997.                 BEGIN
  1998.                   i := fGetTextDITAsInteger(theDialog, cDITScalePercentage);
  1999.                   DisposDialog(theDialog);  {hide dialog before possible alert}
  2000.                   IF fCheckAndCorrected(i) THEN
  2001.                     BEGIN
  2002.                       IF fNotExistingOrNotOurs(theWindow) THEN
  2003.                         BEGIN
  2004.                           vViewScalePercentageDefault := i;
  2005.                         END
  2006.                       ELSE
  2007.                         BEGIN  {set the viewing method of a window}
  2008.                           vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  2009.                           vhWindowRelatedInfo^^.rViewScalePreviewPercentage := i;
  2010.                           
  2011.                           pRetitleWindow(theWindow);  {to reflect scaling in title}
  2012.                           pCalcScaledPageDrawingRect(vhWindowRelatedInfo);
  2013.                           pSetScrollBarLimits(theWindow);
  2014.                           pInvalidateAllOfWindow(theWindow);
  2015.                         END;
  2016.                     END;  {IF entered number ok}
  2017.                 END  {IF OK clicked}
  2018.               ELSE
  2019.                 DisposDialog(theDialog);
  2020.             END;  {IF dialog not NIL}
  2021.         END;  {case Scale Preview}
  2022.     END;  {CASE}
  2023.   END;  {pDoViewMenu}
  2024.   
  2025.   
  2026.   PROCEDURE pDoSettingsMenu(theItem: Integer);
  2027.     VAR
  2028.       theWindow: WindowPtr;
  2029.       vhWindowRelatedInfo: thWindowRelatedInfo;
  2030.       usePrinterSpacing: Boolean;
  2031.       disableFontScaling: Boolean;
  2032.   BEGIN
  2033.     theWindow := FrontWindow;
  2034.     IF fNotExistingOrNotOurs(theWindow) THEN
  2035.       BEGIN
  2036.         usePrinterSpacing := vSettingsUsePrinterSpacing;
  2037.         disableFontScaling := vSettingsDisableFontScaling;
  2038.         CASE theItem OF
  2039.           cSettingsUsePrinterSpacing:
  2040.             BEGIN
  2041.               usePrinterSpacing := NOT usePrinterSpacing;
  2042.               vSettingsUsePrinterSpacing := usePrinterSpacing;
  2043.             END;
  2044.           cSettingsDisableFontScaling:
  2045.             BEGIN
  2046.               disableFontScaling := NOT disableFontScaling;
  2047.               vSettingsDisableFontScaling := disableFontScaling;
  2048.             END;
  2049.         END; {CASE}
  2050.       END
  2051.     ELSE
  2052.       BEGIN  {set the viewing method of a window}
  2053.         vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  2054.         usePrinterSpacing := vhWindowRelatedInfo^^.rUsePrinterSpacing;
  2055.         disableFontScaling := vhWindowRelatedInfo^^.rDisableFontScaling;
  2056.         CASE theItem OF
  2057.           cSettingsUsePrinterSpacing:
  2058.             BEGIN
  2059.               usePrinterSpacing := NOT usePrinterSpacing;
  2060.               vhWindowRelatedInfo^^.rUsePrinterSpacing := usePrinterSpacing;
  2061.             END;
  2062.           cSettingsDisableFontScaling:
  2063.             BEGIN
  2064.               disableFontScaling := NOT disableFontScaling;
  2065.               vhWindowRelatedInfo^^.rDisableFontScaling := disableFontScaling;
  2066.             END;
  2067.         END; {CASE}
  2068.         pInvalidateAllOfWindow(theWindow);
  2069.       END;
  2070.     
  2071.     CheckItem(vMenu[eSettings], cSettingsUsePrinterSpacing, usePrinterSpacing);
  2072.     CheckItem(vMenu[eSettings], cSettingsDisableFontScaling, disableFontScaling);
  2073.   END;  {pDoSettingsMenu}
  2074.  
  2075.  
  2076.   PROCEDURE pDoPageMenu(theItem: Integer);
  2077.     VAR
  2078.       theWindow: WindowPtr;
  2079.       vhWindowRelatedInfo: thWindowRelatedInfo;
  2080.       oldPageNumber: Integer;
  2081.       newPageNumber: Integer;
  2082.       theDialog: DialogPtr;
  2083.       itemHit: Integer;
  2084.   BEGIN
  2085.     theWindow := FrontWindow;
  2086.     IF fNotExistingOrNotOurs(theWindow) THEN
  2087.       Exit;
  2088.     
  2089.     vhWindowRelatedInfo := thWindowRelatedInfo(GetWRefCon(theWindow));
  2090.     oldPageNumber := vhWindowRelatedInfo^^.rPageNumber;
  2091.     CASE theItem OF
  2092.       cPagePrevious:
  2093.         newPageNumber := oldPageNumber - 1;
  2094.       cPageNext:
  2095.         newPageNumber := oldPageNumber + 1;
  2096.       cPageFirst:
  2097.         newPageNumber := 1;
  2098.       cPageLast:
  2099.         newPageNumber := vhWindowRelatedInfo^^.rSpoolFileHeader.pfPgDir.iPages;
  2100.       
  2101.       cPageGotoPage:
  2102.         BEGIN
  2103.           theDialog := GetNewDialog(cDialogGotoPage, NIL, WindowPtr(-1));
  2104.           IF theDialog <> NIL THEN
  2105.             BEGIN
  2106.               pFrameButton(theDialog, cOkButton);
  2107.               pSetTextDITFromInteger(  {from window}
  2108.                 theDialog,
  2109.                 cDITPageNumber,
  2110.                 vhWindowRelatedInfo^^.rPageNumber
  2111.               );
  2112.               SelIText(theDialog, cDITPageNumber, 0, 32767);  {preselect it}
  2113.               ModalDialog( {filterProc=>} NIL, itemHit);
  2114.               
  2115.               IF itemHit = cOkButton THEN
  2116.                 newPageNumber :=
  2117.                   fGetTextDITAsInteger(theDialog, cDITPageNumber)
  2118.               ELSE
  2119.                 newPageNumber := oldPageNumber;
  2120.               
  2121.               DisposDialog(theDialog);
  2122.             END;  {IF dialog not NIL}
  2123.         END;  {case Goto page}
  2124.       
  2125.       OTHERWISE {cPagePageNumberItem:}
  2126.         ;
  2127.     END;  {CASE}
  2128.     vhWindowRelatedInfo^^.rPageNumber := newPageNumber;
  2129.     pChangePageMenuAccordingToWindow(theWindow);
  2130.       {Procedure 'pChangePageMenuAccordingToWindow' calls}
  2131.       {'pNormalizePageNumberAndAdjustPageMenu'.}
  2132.     
  2133.     { If page number really changes, then the whole window needs to be redrawn. }
  2134.     IF oldPageNumber <> vhWindowRelatedInfo^^.rPageNumber THEN
  2135.       pInvalidateAllOfWindow(theWindow);
  2136.   END;  {pDoPageMenu}
  2137.  
  2138.  
  2139.  
  2140. BEGIN  {BatchPrint}
  2141.   { Initialize TransSkel with 10 MoreMasters and no GrowZone procedure. }
  2142.   SkelInit(10, NIL);
  2143.   
  2144.   CouldAlert(cAlertNoMemoryForWindows);
  2145.   CouldAlert(cAlertFileError);
  2146.   CouldAlert(cAlertPrintError);
  2147.   
  2148.   { Desk accessories into standard Apple menu. }
  2149.   hString := GetString(cStringAboutBatchPrint);
  2150.   IF hString = NIL THEN
  2151.     SkelApple('About BatchPrint╔', @pDoAboutBatchPrint)
  2152.   ELSE
  2153.     BEGIN
  2154.     HLock(Handle(hString));
  2155.     SkelApple(hString^^, @pDoAboutBatchPrint);
  2156.     HUnlock(Handle(hString));
  2157.     ReleaseResource(Handle(hString));
  2158.     END;
  2159.   
  2160.   { Fetch menus from resources. }
  2161.   FOR vMenuEnumeration := eFile TO ePage DO
  2162.     vMenu[vMenuEnumeration] := GetMenu(cMenuFirstId+Ord(vMenuEnumeration));
  2163.   successful := SkelMenu(vMenu[eFile], @pDoFileMenu, NIL, False);
  2164.   successful := SkelMenu(vMenu[eEdit], @pDoEditMenu, NIL, False);
  2165.   successful := SkelMenu(vMenu[eView], @pDoViewMenu, NIL, False);
  2166.   successful := SkelMenu(vMenu[eSettings], @pDoSettingsMenu, NIL, False);
  2167.   successful := SkelMenu(vMenu[ePage], @pDoPageMenu, NIL, True);
  2168.   
  2169.   { Default viewing method. }
  2170.   vViewMenuSelectionDefault := cViewInformation;
  2171.   vViewScalePercentageDefault := cViewScalePercentageDefault;
  2172.   pChangeViewMenuAccordingToWindow(NIL);
  2173.   
  2174.   { Check for 128K ROMs. }
  2175.   Environs(romVersion, machineType);
  2176.   vHas128KROMs := (romVersion >= 117);  {IM IV-236}
  2177.   IF NOT vHas128KROMs THEN
  2178.     BEGIN
  2179.       DisableItem(vMenu[eSettings], 0);  {all of it}
  2180.       DrawMenuBar;
  2181.     END;
  2182.   
  2183.   { Defaults for font manager behavior. }
  2184.   vSettingsUsePrinterSpacing := False;
  2185.   vSettingsDisableFontScaling := False;
  2186.   pChangeSettingsMenuAccordingToWindow(NIL);
  2187.   
  2188.   { Default page number. }
  2189.   pChangePageMenuAccordingToWindow(NIL);
  2190.   
  2191.   vNumberOfOurOpenWindows := 0;
  2192.   pMenusToState(eNoOurWindowsOpen);
  2193.   
  2194.   { Check for messages from the Finder. }
  2195.   CountAppFiles(vWhatFinderToldUsToDo, vNumberOfAppFiles);
  2196.   IF vNumberOfAppFiles > 0 THEN
  2197.     BEGIN
  2198.       { Open all the files. }
  2199.       FOR i:=1 TO vNumberOfAppFiles DO
  2200.         BEGIN
  2201.           GetAppFiles(i, theAppFile);
  2202.           IF theAppFile.fType = 'PFIL' THEN
  2203.              pOpenWindowByName(theAppFile.fName, theAppFile.vRefNum);
  2204.           ClrAppFiles(i);  {as instructed by IM II-58}
  2205.         END;  {FOR each file}
  2206.       
  2207.       { If requested to print, print immediately and exit. }
  2208.       IF vWhatFinderToldUsToDo = appPrint THEN
  2209.         BEGIN
  2210.           pDoPrintAll;
  2211.           SkelWhoa;
  2212.         END;
  2213.     END;  {IF files from Finder}
  2214.  
  2215.   { Perform main event loop until 'Quit' from 'File' menu is selected and 'SkelWhoa' called. }
  2216.   SkelMain;
  2217.   
  2218.   { TransSkel clean up. }
  2219.   SkelClobber;
  2220. END.  {BatchPrint}
  2221.